--- Test various map implementations
module examples.MapTest where

-- import frege.Prelude hiding(uniq)
import Data.TreeMap T()
import Data.HashMap HM(HashMap)
import Data.JSON(toJSON)
import Java.Util(HashMap JHM)


main ["count", "tree"] = count  0 >>= println  
main ["uniq", "tree"] = do
    t <- uniqt T.TreeMap.empty
    println $ sum (T.values t)
    println $ T.size t

main ["uniq", "hash"] = do
    t <- uniqh HashMap.empty
    -- println $ sumt t
    println $ sum (HM.values t)
    println $ HM.size t

main ["uniq", "java"] = do
    t <- JHM.new ()
    t <- uniqj t
    t.values >>= _.iterator >>= Util.Iterator.fold (+) 0 >>= println
    t.size >>= println


main ["coll", "hash"] = do
    t <- uniqh HashMap.empty
    println $ HM.foldValues (+) 0 t
    println $ HM.size t
    println $ toJSON (t.collisions)


main ["words"] = thewords

main ["hashtest"] = do
    let e = HashMap.empty :: HashMap Int String
    let hm1 = HM.insert 1 "foo" e
    let hm2 = HM.insert 0x40000001 "bar" hm1
    let hm3 = HM.insert 0x80000001 "foobar" hm2
    println (HashMap.invariants e)
    println (toJSON e)
    println (HashMap.invariants hm1)
    println (toJSON hm1)
    println (HashMap.invariants hm2)
    println (toJSON hm2)
    println (HashMap.invariants hm3)
    println (toJSON hm3)
    let hm4 = HM.delete 1 hm3
    println "after delete 1"
    println (HashMap.invariants hm4)
    println (toJSON hm4)
    let pkv k v = do
            println ("key="++show k++", value="++show v)
    HM.traverseWithKey pkv hm3
    return ()

-- tests.qc.HM.p_filterWithKey: *** Failed! (after 2 tests):              
-- Falsifiable
-- {"BM" : [[{"KV" : [71, 71, 0]}, {"KV" : [147, 147, 0]}], 524416]}

main ["filter"] = do
    let hm = HM.insert 71 0 (HM.insert 147 0 empty)
        p k v = even k == even v
        r  = HM.filterWithKey p hm
    println hm
    println r 
    return ()
{-
Falsifiable (unionWith (-))
{
  "BM" : [
    [
      {"KV" : [33, 33, 2]}, {"KV" : [35, 35, -3]},
      {"KV" : [166, 166, 0]}, {"KV" : [206, 206, -1]},
      {"KV" : [16, 16, -4]}, {"KV" : [50, 50, 2]},
      {"KV" : [211, 211, -3]}, {"KV" : [213, 213, -1]},
      {"BM" : [[{"KV" : [56, 56, 2]}, {"KV" : [120, 120, 3]}], 10]},
      {"KV" : [217, 217, 0]}, {"KV" : [59, 59, 1]},
      {"KV" : [62, 62, -2]}, {"KV" : [159, 159, 3]}
    ],
    -886226870
  ]
}
{
  "BM" : [
    [
      {"KV" : [129, 129, -1]}, {"KV" : [163, 163, 1]},
      {"KV" : [229, 229, -1]}, {"KV" : [166, 166, 1]},
      {"KV" : [73, 73, 3]}, {"KV" : [170, 170, 1]},
      {"KV" : [236, 236, -3]}, {"KV" : [14, 14, 2]},
      {"KV" : [144, 144, -4]}, {"KV" : [119, 119, 3]},
      {"KV" : [57, 57, 0]}, {"KV" : [123, 123, 0]},
      {"KV" : [92, 92, -4]}
    ],
    444683882
  ]
}
-}

main _ = do
        println (toJSON hm1)
        println (toJSON hm2)
        println (toJSON hm)
        mapM_ com common
    where
        com k = do
            print ("key: " ++ show k ++ "  ")
            print (HM.lookup k hm1)
            print " - "
            print (HM.lookup k hm2)
            print " == "
            print (HM.lookup k hm)
            println "?"
        kvhm hm (k,v) = HM.insert k v hm
        hm1 = fold kvhm empty kv1
        hm2 = fold kvhm empty kv2
        hm  = HM.unionWith (-) hm1 hm2
        common = [ k | k <- HM.keys hm, k HM.`member` hm1, k HM.`member` hm2]
        kv1 = [
            -- (33,2), (35,-3), 
            (166,0), 
            -- (206,-1), (16,-4), (50,2),
            -- (211, -3), (213, -1), (56,2), (120,3),
            -- (217, 0), (59,1), (62,-2), (159,3),
            ]
        kv2 = [
            -- (129,-1), (163,1), (229, -1), 
            (166, 1),
            -- (73,3), (170,1), (236, -3), (14,2),
            -- (144, -4), (119, 3),
            -- (57, 0), (123, 0),
            -- (92, -4),
            ]


thewords :: IO ()
thewords = do
        more ← stdin.readLine
        case more of
            Just line → do
                mapM_ println (
                    zipWith (++) 
                        (cycle (map ctos ['!'..'~'])) 
                        (line ~~* '\w+')) 
                thewords
            Nothing   → return ()

uniqt :: T.TreeMap String Int -> IO (T.TreeMap String Int)
uniqt !tree = do
        more ← stdin.readLine
        case more of
            Just line → uniqt (T.insertWith (+) line 1 tree) -- uniqt (process tree line)
            Nothing   → return tree


uniqj :: MutableIO (JHM String Int) -> IOMutable (JHM String Int)
uniqj !jmh = do
        more ← stdin.readLine
        case more of
            Just line → do
                v <- jmh.get line
                jmh.put line (maybe 1 (1+) v)
                uniqj jmh
            Nothing   → return jmh

private pure native sumHashMap MapTest.sumHM :: JHM String Int -> Int
native module where {
    static int sumHM(java.util.HashMap<java.lang.String, java.lang.Integer> hm) {
        int sum = 0;
        for (Integer i : hm.values()) {
            sum += i;
        }
        return sum;
    }
}

uniqh :: HashMap String Int -> IO (HashMap String Int)
uniqh !hmap = do
        more ← stdin.readLine
        case more of
            Just line → uniqh (HM.insertWith (+) line 1 hmap)
            Nothing   → return hmap

count !e = 
        fmap addwords <$> stdin.readLine 
            >>= maybe (return e) count
    where
        addwords s = e + length (s ~~* '\w+') 

